package org.cx.comparator.compare.mode.impl;

import org.cx.comparator.ComparatorException;
import org.cx.comparator.ComparatorMethod;
import org.cx.comparator.compare.mode.ComparatorMode;
import org.cx.comparator.compare.mode.ComparatorModeContext;
import org.cx.comparator.expression.ExpressionInvoker;
import org.cx.comparator.expression.QLExpressionInvoker;
import org.cx.comparator.map.ComparatorFieldMapping;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.util.HashMap;
import java.util.Map;


@Slf4j
public class ExpressionComparatorMode implements ComparatorMode, ApplicationContextAware {

    private ExpressionInvoker expressionInvoker = QLExpressionInvoker.INSTANCE;


    @Override
    public boolean equatorMode(ComparatorModeContext comparatorModeContext) {
        final ComparatorFieldMapping comparatorFieldMapping = comparatorModeContext.getComparatorFieldMapping();
        final Object source = comparatorModeContext.getSource();
        final String target = comparatorFieldMapping.getTarget();
        final String expression = comparatorFieldMapping.getExpression();
        if (StringUtils.isBlank(expression)) {
            log.warn("source={},target={}进行比较时，表达式为空！将直接返回False", comparatorFieldMapping.getSource(), comparatorFieldMapping.getTarget());
            return false;
        } else {
            final Object retVal = invokeExpression(comparatorModeContext, source, target, expression);
            if (retVal != null && retVal instanceof Boolean) {
                return (boolean) retVal;
            } else {
                throw new ComparatorException("source=" + comparatorFieldMapping.getSource() + ",target=" + comparatorFieldMapping.getTarget() + "进行比较时，表达式返回值不是布尔类型！");
            }
        }
    }

    private Object invokeExpression(ComparatorModeContext comparatorModeContext, Object source, String target, String expression) {
        Map<String, Object> args = new HashMap<>(2);
        args.put("source", source);
        args.put("target", target);

        final ComparatorMethod comparatorMethod = comparatorModeContext.getComparatorMethod();
        final Map<Integer, String> params = comparatorMethod.getParams();
        for (Map.Entry<Integer, String> entry : params.entrySet()) {
            args.put(entry.getValue(), comparatorModeContext.getInvokeMethodArgs()[entry.getKey()]);
        }

        return expressionInvoker.invoke(expression, args);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (expressionInvoker instanceof QLExpressionInvoker) {
            ((QLExpressionInvoker) expressionInvoker).setApplicationContext(applicationContext);
        }
    }
}
